001    /*
002     * Copyright 2003-2005 The Apache Software Foundation
003     * Copyright 2005 Stephen McConnell
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package net.dpml.cli.builder;
018    
019    import java.util.ArrayList;
020    import java.util.List;
021    
022    import net.dpml.cli.Argument;
023    import net.dpml.cli.option.ArgumentImpl;
024    import net.dpml.cli.resource.ResourceConstants;
025    import net.dpml.cli.resource.ResourceHelper;
026    import net.dpml.cli.validation.Validator;
027    
028    /**
029     * Builds Argument instances.
030     *
031     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
032     * @version 1.0.0
033     */
034    public class ArgumentBuilder
035    {
036        /** i18n */
037        private static final ResourceHelper RESOURCES = ResourceHelper.getResourceHelper();
038        
039        /** name of the argument. Used for display and lookups in CommandLine */
040        private String m_name;
041    
042        /** description of the argument. Used in the automated online help */
043        private String m_description;
044    
045        /** minimum number of values required */
046        private int m_minimum;
047    
048        /** maximum number of values permitted */
049        private int m_maximum;
050    
051        /** character used to separate the values from the option */
052        private char m_initialSeparator;
053    
054        /** character used to separate the values from each other */
055        private char m_subsequentSeparator;
056    
057        /** object that should be used to ensure the values are valid */
058        private Validator m_validator;
059    
060        /** used to identify the consume remaining option, typically "--" */
061        private String m_consumeRemaining;
062    
063        /** default values for argument */
064        private List m_defaultValues;
065    
066        /** id of the argument */
067        private int m_id;
068    
069        /**
070         * Creates a new ArgumentBuilder instance
071         */
072        public ArgumentBuilder()
073        {
074            reset();
075        }
076    
077        /**
078         * Creates a new Argument instance using the options specified in this
079         * ArgumentBuilder.
080         * 
081         * @return A new Argument instance using the options specified in this
082         * ArgumentBuilder.
083         */
084        public final Argument create()
085        {
086            final Argument argument =
087                new ArgumentImpl(
088                  m_name,
089                  m_description,
090                  m_minimum,
091                  m_maximum,
092                  m_initialSeparator,
093                  m_subsequentSeparator,
094                  m_validator,
095                  m_consumeRemaining,
096                  m_defaultValues,
097                  m_id );
098            reset();
099            return argument;
100        }
101    
102        /**
103         * Resets the ArgumentBuilder to the defaults for a new Argument. The
104         * method is called automatically at the end of a create() call.
105         * @return the argument builder
106         */
107        public final ArgumentBuilder reset()
108        {
109            m_name = "arg";
110            m_description = null;
111            m_minimum = 0;
112            m_maximum = Integer.MAX_VALUE;
113            m_initialSeparator = ArgumentImpl.DEFAULT_INITIAL_SEPARATOR;
114            m_subsequentSeparator = ArgumentImpl.DEFAULT_SUBSEQUENT_SEPARATOR;
115            m_validator = null;
116            m_consumeRemaining = "--";
117            m_defaultValues = null;
118            m_id = 0;
119            return this;
120        }
121    
122        /**
123         * Sets the name of the argument. The name is used when displaying usage
124         * information and to allow lookups in the CommandLine object.
125         * 
126         * @see net.dpml.cli.CommandLine#getValue(String)
127         * 
128         * @param newName the name of the argument
129         * @return this ArgumentBuilder
130         */
131        public final ArgumentBuilder withName( final String newName )
132        {
133            if( newName == null )
134            {
135                throw new IllegalArgumentException(
136                  RESOURCES.getMessage(
137                    ResourceConstants.ARGUMENT_BUILDER_NULL_NAME ) );
138            }
139            if( "".equals( newName ) )
140            {
141                throw new IllegalArgumentException(
142                  RESOURCES.getMessage(
143                    ResourceConstants.ARGUMENT_BUILDER_EMPTY_NAME ) );
144            }
145            m_name = newName;
146            return this;
147        }
148    
149        /**
150         * Sets the description of the argument.
151         * 
152         * The description is used when displaying online help.
153         * 
154         * @param newDescription a description of the argument
155         * @return this ArgumentBuilder
156         */
157        public final ArgumentBuilder withDescription( final String newDescription )
158        {
159            m_description = newDescription;
160            return this;
161        }
162    
163        /**
164         * Sets the minimum number of values needed for the argument to be valid.
165         * 
166         * @param newMinimum the number of values needed
167         * @return this ArgumentBuilder
168         */
169        public final ArgumentBuilder withMinimum( final int newMinimum )
170        {
171            if( newMinimum < 0 )
172            {
173                throw new IllegalArgumentException(
174                  RESOURCES.getMessage(
175                    ResourceConstants.ARGUMENT_BUILDER_NEGATIVE_MINIMUM ) );
176            }
177            m_minimum = newMinimum;
178            return this;
179        }
180    
181        /**
182         * Sets the maximum number of values allowed for the argument to be valid.
183         * 
184         * @param newMaximum the number of values allowed
185         * @return this ArgumentBuilder
186         */
187        public final ArgumentBuilder withMaximum( final int newMaximum )
188        {
189            if( newMaximum < 0 )
190            {
191                throw new IllegalArgumentException(
192                  RESOURCES.getMessage(
193                    ResourceConstants.ARGUMENT_BUILDER_NEGATIVE_MAXIMUM ) );
194            }
195            m_maximum = newMaximum;
196            return this;
197        }
198    
199        /**
200         * Sets the character used to separate the values from the option. When an
201         * argument is of the form -libs:dir1,dir2,dir3 the initialSeparator would
202         * be ':'.
203         * 
204         * @param newInitialSeparator the character used to separate the values 
205         * from the option
206         * @return this ArgumentBuilder
207         */
208        public final ArgumentBuilder withInitialSeparator(
209            final char newInitialSeparator )
210        {
211            m_initialSeparator = newInitialSeparator;
212            return this;
213        }
214    
215        /**
216         * Sets the character used to separate the values from each other. When an
217         * argument is of the form -libs:dir1,dir2,dir3 the subsequentSeparator
218         * would be ','.
219         * 
220         * @param newSubsequentSeparator the character used to separate the values 
221         * from each other
222         * @return this ArgumentBuilder
223         */
224        public final ArgumentBuilder withSubsequentSeparator(
225            final char newSubsequentSeparator )
226        {
227            m_subsequentSeparator = newSubsequentSeparator;
228            return this;
229        }
230    
231        /**
232         * Sets the validator instance used to perform validation on the Argument
233         * values.
234         * 
235         * @param newValidator a Validator instance
236         * @return this ArgumentBuilder
237         */
238        public final ArgumentBuilder withValidator( final Validator newValidator )
239        {
240            if( newValidator == null )
241            {
242                throw new IllegalArgumentException(
243                  RESOURCES.getMessage(
244                    ResourceConstants.ARGUMENT_BUILDER_NULL_VALIDATOR ) );
245            }
246            m_validator = newValidator;
247            return this;
248        }
249    
250        /**
251         * Sets the "consume remaining" option, defaults to "--". Use this if you
252         * want to allow values that might be confused with option strings.
253         * 
254         * @param newConsumeRemaining the string to use for the consume 
255         * remaining option
256         * @return this ArgumentBuilder
257         */
258        public final ArgumentBuilder withConsumeRemaining( final String newConsumeRemaining )
259        {
260            if( newConsumeRemaining == null )
261            {
262                throw new IllegalArgumentException(
263                  RESOURCES.getMessage(
264                    ResourceConstants.ARGUMENT_BUILDER_NULL_CONSUME_REMAINING ) );
265            } 
266            if( "".equals( newConsumeRemaining ) )
267            {
268                throw new IllegalArgumentException(
269                  RESOURCES.getMessage(
270                    ResourceConstants.ARGUMENT_BUILDER_EMPTY_CONSUME_REMAINING ) );
271            }
272            m_consumeRemaining = newConsumeRemaining;
273            return this;
274        }
275    
276        /**
277         * Sets the default value.
278         * 
279         * @param defaultValue the default value for the Argument
280         * @return this ArgumentBuilder
281         */
282        public final ArgumentBuilder withDefault( final Object defaultValue )
283        {
284            if( defaultValue == null )
285            {
286                throw new IllegalArgumentException(
287                  RESOURCES.getMessage(
288                    ResourceConstants.ARGUMENT_BUILDER_NULL_DEFAULT ) );
289            }
290            
291            if( m_defaultValues == null )
292            {
293                m_defaultValues = new ArrayList( 1 );
294            }
295            m_defaultValues.add( defaultValue );
296            return this;
297        }
298    
299        /**
300         * Sets the default values.
301         * 
302         * @param newDefaultValues the default values for the Argument
303         * @return this ArgumentBuilder
304         */
305        public final ArgumentBuilder withDefaults( final List newDefaultValues )
306        {
307            if( newDefaultValues == null )
308            {
309                throw new IllegalArgumentException(
310                  RESOURCES.getMessage(
311                    ResourceConstants.ARGUMENT_BUILDER_NULL_DEFAULTS ) );
312            }
313            m_defaultValues = newDefaultValues;
314            return this;
315        }
316    
317        /**
318         * Sets the id
319         * 
320         * @param newId the id of the Argument
321         * @return this ArgumentBuilder
322         */
323        public final ArgumentBuilder withId( final int newId )
324        {
325            m_id = newId;
326            return this;
327        }
328    }